package com.xinqi.modules.course.clazz.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xinqi.common.base.enums.YesNoEnum;
import com.xinqi.common.base.enums.YesNoNumberEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.utils.lambda.Lambdas;
import com.xinqi.common.base.utils.spring.Spring;
import com.xinqi.common.core.enums.ClassRoleEnum;
import com.xinqi.common.mybatis.data.service.impl.BaseServiceImpl;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.common.satoken.utils.LoginHelper;
import com.xinqi.modules.course.clazz.convert.ClassGroupConvert;
import com.xinqi.modules.course.clazz.convert.ClassGroupStudentConvert;
import com.xinqi.modules.course.clazz.domain.ClassGroupEntity;
import com.xinqi.modules.course.clazz.domain.ClassGroupStudentEntity;
import com.xinqi.modules.course.clazz.dto.req.*;
import com.xinqi.modules.course.clazz.dto.rsp.ClassGroupResultDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassGroupStudentResultDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassStudentResultDTO;
import com.xinqi.modules.course.clazz.mapper.ClassGroupMapper;
import com.xinqi.modules.course.clazz.service.*;
import com.xinqi.modules.course.course.constant.CourseConstants;
import com.xinqi.modules.course.course.enums.group.GroupCreatedTypeEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 班级分组表服务层实现
 *
 * @author: system
 * @date: 2023/01/17
 */
@Slf4j
@Service("classGroupService")
@RequiredArgsConstructor
public class ClassGroupServiceImpl extends BaseServiceImpl<ClassGroupMapper, ClassGroupEntity> implements ClassGroupService {
    private final ClassGroupConvert classGroupConvert;
    private final ClassGroupStudentConvert classGroupStudentConvert;
    @Lazy
    private final ClassStudentService classStudentService;
    @Lazy
    private final ClassGroupStudentService classGroupStudentService;
    private final ClassService classService;
    @Lazy
    private final ChatRemindSyncService chatRemindSyncService;

    /**
     * 分页查询 班级分组表数据
     */
    @Override
    @DS("slaver")
    public PageInfo<ClassGroupResultDTO> page(Param pageable, ClassGroupQueryDTO query) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(query.getClassId()), "班级id不能为空");
        PageInfo<ClassGroupResultDTO> pageList = Pages.convert(page(Pages.page(pageable), wrapper(query)), classGroupConvert::convert);
        //设置班级学生数量
        this.setTotalCount(query.getClassId(), pageList.getRows());
        Lambdas.each(pageList.getRows(), classGroupConvert::renderClassStudentCount);
        return pageList;
    }

    @Override
    public List<ClassGroupResultDTO> findChildrenListByPid(Long pid) {
        List<ClassGroupResultDTO> classGroupList = baseMapper.findChildrenListByPid(pid);
        if (CollectionUtils.isNotEmpty(classGroupList)) {
            ClassStudentResultDTO classMasterStudent = classStudentService.findVirtualClassStudentByClassIdAndUserId(classGroupList.get(0).getClassId(), LoginHelper.getUserId());
            Long studentId = Objects.isNull(classMasterStudent) ? LoginHelper.getUserId() : classMasterStudent.getStudentId();
            ClassGroupStudentResultDTO mine = classGroupStudentService.findByPidAndStudentId(pid, studentId);
            if (Objects.nonNull(mine)) {
                classGroupList.forEach(group -> {
                    if (Objects.equals(mine.getGroupId(), group.getId())) {
                        group.setJoinedStatus(YesNoEnum.YES.ordinal());
                    }
                });
            }
        }
        return classGroupList;
    }

    private void setTotalCount(Long classId, List<ClassGroupResultDTO> groupList) {
        int totalStudentCount = classGroupStudentService.findClassTotalStudentCount(classId);
        for (ClassGroupResultDTO group : groupList) {
            group.setTotal(totalStudentCount);
        }
    }

    @Override
    public Long findChildrenGroupNum(Long classId, Long pid) {
        ClassGroupQueryDTO queryDTO = new ClassGroupQueryDTO();
        queryDTO.setClassId(classId);
        queryDTO.setPid(pid);
        return this.count(wrapper(queryDTO));
    }

    /**
     * 查询 班级分组表数据
     */
    @Override
    public List<ClassGroupResultDTO> find(ClassGroupQueryDTO query) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(query.getClassId()), "班级id不能为空");
        return list(wrapper(query)).stream().map(classGroupConvert::convert).collect(Collectors.toList());
    }

    private LambdaQueryWrapper<ClassGroupEntity> wrapper(ClassGroupQueryDTO query) {
        LambdaQueryWrapper<ClassGroupEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(ClassGroupEntity::getId, v));
        Queries.accept(query.getClassId(), v -> wrapper.eq(ClassGroupEntity::getClassId, v));
        Queries.accept(query.getPid(), v -> wrapper.eq(ClassGroupEntity::getPid, v));
        Queries.accept(query.getSign(), v -> wrapper.eq(ClassGroupEntity::getSign, v));
        Queries.accept(query.getType(), v -> wrapper.eq(ClassGroupEntity::getType, v));
        wrapper.orderBy(true, true, ClassGroupEntity::getType);
        wrapper.orderBy(true, false, ClassGroupEntity::getLastTime);
        return wrapper;
    }

    private LambdaQueryWrapper<ClassGroupEntity> wrapperByClassIdAndTypes(Long classId, Long pid, List<String> types) {
        LambdaQueryWrapper<ClassGroupEntity> wrapper = Queries.lambda();
        Queries.accept(classId, v -> wrapper.eq(ClassGroupEntity::getClassId, v));
        Queries.accept(pid, v -> wrapper.eq(ClassGroupEntity::getPid, v));
        Queries.accept(types, v -> wrapper.in(ClassGroupEntity::getType, v));
        return wrapper;
    }

    /**
     * 根据id查询 班级分组表数据，如果是父分组，设置子分组和学生，如果是子分组直接设置学生
     */
    @Override
    public ClassGroupResultDTO findById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return Optional.ofNullable(baseMapper.selectById(id)).map(classGroupConvert::convert).orElse(null);
    }

    /**
     * 新增父分组
     *
     * @param dto
     * @return
     */
    private Long insertParentGroup(ClassGroupCreateDTO dto) {
        ClassGroupEntity entity = classGroupConvert.create(dto);
        save(entity);
        return entity.getId();
    }

    /**
     * 新增小组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(ClassGroupCreateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getName()), "小组名称不能为空");
        //校验为本班学生
        ClassStudentResultDTO studentEntity = classStudentService.checkRole(dto.getClassId(), dto.getOperationUserId(), null);
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getPid()), "父id不能为空");
        ClassGroupEntity parent = Optional.ofNullable(baseMapper.selectById(dto.getPid())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("父分组不存在"));

        CommonErrors.BAD_REQUEST.check(!isExistsByName(dto.getClassId(), dto.getPid(), dto.getName(), null), "小组名称不可重复");

        List<ClassStudentResultDTO> studentList = classStudentService.findStudentExcludeTeacher(dto.getClassId());
        Long existGroupNum = findChildrenGroupNum(dto.getClassId(), dto.getPid());
        CommonErrors.BAD_REQUEST.check(existGroupNum < studentList.size(), "小组数不能大于班级人数");

        ClassGroupEntity son = new ClassGroupEntity();
        son.setLastTime(parent.getLastTime());
        son.setCourseId(parent.getCourseId());
        son.setClassId(parent.getClassId());
        son.setPid(parent.getId());
        son.setType(parent.getType());
        son.setRule(dto.getRule());
        son.setName(dto.getName());
        save(son);

        return son.getId();
    }

    @Override
    public ClassGroupResultDTO insertApp(ClassGroupCreateDTO dto) {
        Long id = this.insert(dto);
        return this.findById(id);
    }

    /**
     * 根据id修改 班级分组表数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateById(ClassGroupUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getId()), "ID不能为空");
        ClassGroupResultDTO groupResult = Optional.ofNullable(findById(dto.getId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));

        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getName()), "小组名称不能为空");

        boolean isExist = this.isExistsByName(groupResult.getClassId(), groupResult.getPid(), dto.getName(), groupResult.getId());
        CommonErrors.BAD_REQUEST.check(!isExist, "小组名称不可重复");

        ClassGroupEntity entity = classGroupConvert.update(dto);
        return updateById(entity);
    }

    /**
     * 根据id删除 班级分组表数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return removeById(id);
    }

    /**
     * 根据id删除 班级分组表数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(ClassGroupDeleteDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getId()), "ID不能为空");
        return deleteById(dto.getId());
    }

    @Override
    public Boolean isExistsByName(Long classId, Long pid, String groupName, Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(classId), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(StringUtils.isNotBlank(groupName), "分组名称不能为空");
        LambdaQueryWrapper<ClassGroupEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassGroupEntity::getClassId, classId);
        wrapper.eq(ClassGroupEntity::getName, groupName);
        if (pid != null) {
            wrapper.eq(ClassGroupEntity::getPid, pid);
        }
        if (id != null) {
            wrapper.ne(ClassGroupEntity::getId, id);
        }
        return count(wrapper) > 0;
    }

    /**
     * 创建自由分组
     *
     * @param dto
     * @return Long
     */
    @Transactional(rollbackFor = Exception.class)
    public Long createdFree(ClassGroupCreateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getLastTime()), "截止时间不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getName()), "分组名称不能为空");

        List<ClassRoleEnum> classRoles = new ArrayList<>();
        classRoles.add(ClassRoleEnum.TEACHER);
        classRoles.add(ClassRoleEnum.ASSISTANT);
        //校验为本班学生
        ClassStudentResultDTO studentEntity = classStudentService.checkRole(dto.getClassId(), dto.getOperationUserId(), classRoles);

        long existFreedomCount = this.findParentGroupCountByClassId(dto.getClassId(), GroupCreatedTypeEnum.FREEDOM.getCode());
        CommonErrors.BAD_REQUEST.check(existFreedomCount < CourseConstants.GroupCount.SINGLE_COUNT, "同一班级下自由分组的个数不能超过3个");

        long existTotalCount = this.findParentGroupCountByClassId(dto.getClassId(), null);
        CommonErrors.BAD_REQUEST.check(existTotalCount < CourseConstants.GroupCount.TOTAL_COUNT, "同一班级下所有分组的个数总和不能超过6个");

        CommonErrors.BAD_REQUEST.check(!this.isExistsByName(dto.getClassId(), null, dto.getName(), null), "小组名称不可重复");

        dto.setType(GroupCreatedTypeEnum.FREEDOM.getCode());
        Long groupId = insertParentGroup(dto);

        Spring.committed(() -> chatRemindSyncService.freeGroup(dto.getClassId(), dto.getName(), LoginHelper.getNickname()));

        return groupId;
    }

    /**
     * 老师创建指定分组，
     *
     * @param dto 分组参数
     * @return 返回创建好的组的id
     */
    @Transactional(rollbackFor = Exception.class)
    public Long createdSpecified(ClassGroupCreateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级id不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getName()), "分组名称不能为空");

        List<ClassRoleEnum> classRoles = new ArrayList<>();
        classRoles.add(ClassRoleEnum.TEACHER);
        classRoles.add(ClassRoleEnum.ASSISTANT);
        //校验为本班学生
        ClassStudentResultDTO studentEntity = classStudentService.checkRole(dto.getClassId(), dto.getOperationUserId(), classRoles);

        List<String> types = new ArrayList<>();
        types.add(GroupCreatedTypeEnum.RANDOM.getCode());
        types.add(GroupCreatedTypeEnum.SPECIFIED.getCode());
        long existFreedomCount = this.findParentGroupCountByClassIdAndTypes(dto.getClassId(), types);
        CommonErrors.BAD_REQUEST.check(existFreedomCount < CourseConstants.GroupCount.SINGLE_COUNT, "同一班级下老师分组的个数不能超过3个");

        long existTotalCount = this.findParentGroupCountByClassId(dto.getClassId(), null);
        CommonErrors.BAD_REQUEST.check(existTotalCount < CourseConstants.GroupCount.TOTAL_COUNT, "同一班级下所有分组的个数总和不能超过6个");

        CommonErrors.BAD_REQUEST.check(!this.isExistsByName(dto.getClassId(), null, dto.getName(), null), "小组名称不可重复");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getGroupNum()), "分组数不能为空");

        List<ClassStudentResultDTO> studentList = classStudentService.findStudentExcludeTeacher(dto.getClassId());
        CommonErrors.BAD_REQUEST.check(studentList.size() / dto.getGroupNum() > 0, "学生人数少于分组人数");

        dto.setMaxGroupNum(dto.getGroupNum());
        dto.setType(GroupCreatedTypeEnum.SPECIFIED.getCode());
        //保存父分组
        Long id = insertParentGroup(dto);
        //保存子分组
        dto.setId(id);

        this.batchInsertSon(dto);

        return id;
    }

    /**
     * 系统随机分组，未分组学生应该是班级总学生，除去该组中已经进组的同学
     *
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Long createdRandom(ClassGroupCreateDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getClassId()), "班级ID不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getGroupNum()), "分组数不能为空");
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getName()), "分组名称不能为空");

        List<ClassRoleEnum> classRoles = new ArrayList<>();
        classRoles.add(ClassRoleEnum.TEACHER);
        classRoles.add(ClassRoleEnum.ASSISTANT);
        //校验为本班学生
        ClassStudentResultDTO studentEntity = classStudentService.checkRole(dto.getClassId(), dto.getOperationUserId(), classRoles);

        long existTotalCount = this.findParentGroupCountByClassId(dto.getClassId(), null);
        CommonErrors.BAD_REQUEST.check(existTotalCount < CourseConstants.GroupCount.TOTAL_COUNT, "同一班级下所有分组的个数总和不能超过6个");

        List<String> types = new ArrayList<>();
        types.add(GroupCreatedTypeEnum.RANDOM.getCode());
        types.add(GroupCreatedTypeEnum.SPECIFIED.getCode());
        long existFreedomCount = this.findParentGroupCountByClassIdAndTypes(dto.getClassId(), types);
        CommonErrors.BAD_REQUEST.check(existFreedomCount < CourseConstants.GroupCount.SINGLE_COUNT, "同一班级下老师分组的个数不能超过3个");

        CommonErrors.BAD_REQUEST.check(!this.isExistsByName(dto.getClassId(), null, dto.getName(), null), "小组名称不可重复");

        List<ClassStudentResultDTO> studentList = classStudentService.findStudentExcludeTeacher(dto.getClassId());
        CommonErrors.BAD_REQUEST.check(studentList.size() / dto.getGroupNum() > 0, "学生人数少于分组人数");

        dto.setMaxGroupNum(dto.getGroupNum());
        dto.setType(GroupCreatedTypeEnum.RANDOM.getCode());
        //保存父分组
        Long id = insertParentGroup(dto);
        //保存子分组
        dto.setId(id);

        List<Long> sonIdList = this.batchInsertSon(dto);

        //将学生加到分组中，
        randomSaveStudentList(id, sonIdList, studentList);

        Spring.committed(() -> chatRemindSyncService.randomGroup(dto.getClassId(), dto.getName(), sonIdList));
        return id;
    }

    @Transactional(rollbackFor = Exception.class)
    public List<Long> batchInsertSon(ClassGroupCreateDTO dto) {
        List<ClassGroupEntity> sonList = new ArrayList<>();
        if (dto.getGroupNum() > 0) {
            for (int i = 0; i < dto.getGroupNum(); i++) {
                ClassGroupEntity entity = classGroupConvert.create(dto);
                entity.setName(i + 1 + "组");
                entity.setCreateTime(LocalDateTime.now());
                entity.setId(null);
                entity.setPid(dto.getId());
                sonList.add(entity);
            }
        }
        super.saveBatch(sonList);
        return sonList.stream().map(ClassGroupEntity::getId).collect(Collectors.toList());
    }

    private void randomSaveStudentList(Long pid, List<Long> groupIdList, List<ClassStudentResultDTO> studentList) {
        List<ClassGroupStudentCreateDTO> groupStudentList = new ArrayList<>();

        for (int i = 0; i < studentList.size(); i++) {
            Long groupId = groupIdList.get(i % groupIdList.size());
            ClassStudentResultDTO student = studentList.get(i);
            ClassGroupStudentCreateDTO studentGroup = classGroupStudentConvert.create(student, groupId);
            studentGroup.setPid(pid);
            groupStudentList.add(studentGroup);
        }

        classGroupStudentService.randomSaveStudent(groupStudentList);
    }


    /**
     * 根据id删除 班级分组表数据，并将小组下的学生一起删除，逻辑删除分组，物理删除学生，
     * 删除顺序：先删除学生，再删除小组，再删除分组(父级分组)，如果学生直接属于父分组，也是先删除学生再删除分组。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean remove(Long id) {

        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        ClassGroupEntity groupEntity = Optional.ofNullable(getById(id)).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));

        //分组下的小组
        List<ClassGroupResultDTO> classGroupList = findListByPid(id);

        // 如果分组下有子组，则查询学生，删除学生
        if (CollectionUtils.isNotEmpty(classGroupList)) {
            List<Long> idList = classGroupList.stream().map(ClassGroupResultDTO::getId).collect(Collectors.toList());
            //删除学生
            classGroupStudentService.deleteByGroupId(idList, groupEntity);
            //删除子分组
            removeBatchByIds(classGroupList.stream().map(ClassGroupResultDTO::getId).collect(Collectors.toList()));
        }

        //如果要删除的是小组，小组下有学生删除学生
        List<ClassGroupStudentEntity> studentList = classGroupStudentService.findListByGroupId(groupEntity.getId());
        if (CollectionUtils.isNotEmpty(studentList)) {
            List<Long> studentIds = studentList.stream().map(ClassGroupStudentEntity::getStudentId).collect(Collectors.toList());
            //删除学生
            classGroupStudentService.deleteByGroupId(id, studentIds, groupEntity);
        }

        //删除分组
        return removeById(id);
    }

    @Override
    public ClassGroupResultDTO findOne(ClassGroupQueryDTO query) {
        ClassGroupEntity entity = getOne(wrapper(query));
        return classGroupConvert.convert(entity);
    }

    @Override
    public List<ClassGroupResultDTO> findListByPid(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        LambdaQueryWrapper<ClassGroupEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ClassGroupEntity::getPid, id);
        return list(wrapper).stream().map(classGroupConvert::convert).collect(Collectors.toList());
    }

    @Override
    public ClassGroupEntity findParentById(Long id) {
        return baseMapper.findParentById(id);
    }

    /**
     * 老师分组，如果打开了系统随机分组开关就是系统随机分组，否则就是老师分组
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long teacherGrouping(ClassGroupCreateDTO dto) {
        if (Objects.equals(YesNoEnum.YES.ordinal(), dto.getIsRandom())) {
            return createdRandom(dto);
        }
        return createdSpecified(dto);
    }

    /**
     * 学生自由分组
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long studentFreeGrouping(ClassGroupCreateDTO dto) {
        return this.createdFree(dto);
    }

    @Override
    public List<ClassGroupResultDTO> findTree(ClassGroupQueryDTO dto) {
        return classGroupConvert.rendTree(this.find(dto));
    }

    @Override
    public ClassGroupResultDTO findByGroupStudentId(Long stuId) {
        return baseMapper.findByGroupStudentId(stuId);
    }

    @Override
    public ClassGroupResultDTO findByPidAndSign(ClassGroupSignQueryDTO dto) {
        ClassGroupEntity parent = Optional.ofNullable(getById(dto.getPid())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("父分组不存在"));
        CommonErrors.BAD_REQUEST.check(Objects.equals(parent.getPid(), 0L), "参数错误，自由分组必须必须选中父分组");

        ClassGroupQueryDTO query = new ClassGroupQueryDTO();
        query.setPid(dto.getPid());
        query.setSign(dto.getSign());

        ClassGroupResultDTO result = baseMapper.findByPidAndSign(dto);
        if (!Objects.isNull(result)) {
            ClassGroupStudentQueryDTO studentQuery = new ClassGroupStudentQueryDTO();
            studentQuery.setGroupId(result.getId());
            List<ClassGroupStudentResultDTO> studentList = classGroupStudentService.findStudentList(studentQuery);
            result.setStudentList(studentList);
        }

        return result;

    }

    /**
     * 这个接口是分页树，只能先对父分组进行分页，后根据返回的父分组查询子分组列表
     *
     * @param pageable
     * @param dto
     * @return
     */
    @Override
    @DS("slaver")
    public PageInfo<ClassGroupResultDTO> subChildrenPageList(Param pageable, ClassGroupQueryDTO dto) {

        // 校验班级是否存在
        Optional.ofNullable(classService.findById(dto.getClassId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("班级不存在"));

        dto.setPid(0L);
        PageInfo<ClassGroupResultDTO> pageList = Pages.convert(page(Pages.page(pageable), wrapper(dto)), classGroupConvert::convert);
        if (CollectionUtils.isNotEmpty(pageList.getRows())) {
            Integer total = classStudentService.findStudentExcludeTeacher(dto.getClassId()).size();
            pageList.getRows().forEach(row -> row.setTotal(total));

            //模拟用户信息
            ClassStudentResultDTO classMasterStudent = classStudentService.findVirtualClassStudentByClassIdAndUserId(dto.getClassId(), LoginHelper.getUserId());
            Long studentId = Objects.isNull(classMasterStudent) ? LoginHelper.getUserId() : classMasterStudent.getStudentId();

            //设置子分组和学生
            Lambdas.each(pageList.getRows(), row -> classGroupConvert.renderChildren(row, studentId));

            //设置进组状态
            Lambdas.each(pageList.getRows(), row -> classGroupConvert.renderParentJoinStatus(row, studentId));

            //设置已进组学生和未进组学生
            Lambdas.each(pageList.getRows(), classGroupConvert::renderJoinedCount);

            // 重新排序 将未加入自由分组放到首位
            pageList.setRows(classGroupConvert.swapGroupOrder(pageList.getRows()));
        }

        return pageList;
    }

    @Override
    public ClassGroupResultDTO findDetailById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        ClassGroupResultDTO groupResult = Optional.ofNullable(baseMapper.selectById(id)).map(classGroupConvert::convert).orElse(null);

        if (Objects.nonNull(groupResult)) {

            List<ClassGroupResultDTO> classGroupList = findListByPid(id);
            if (CollectionUtils.isNotEmpty(classGroupList)) {

                List<ClassGroupResultDTO> sortedChildren = classGroupList.stream().sorted(Comparator.comparing(ClassGroupResultDTO::getCreateTime))
                    .collect(Collectors.toList());
                //设置子分组
                groupResult.setChildren(sortedChildren);

                // 获取主学生信息
                ClassStudentResultDTO mainStudent = classStudentService.findVirtualClassStudentByClassIdAndUserId(groupResult.getClassId(), LoginHelper.getUserId());
                Long studentId = Objects.nonNull(mainStudent) ? mainStudent.getStudentId() : LoginHelper.getUserId();
                // 校验学生是否加入小组
                List<Long> groupIds = classGroupList.stream().map(ClassGroupResultDTO::getId).collect(Collectors.toList());
                List<ClassGroupStudentEntity> list = classGroupStudentService.checkStudentInGroup(groupIds, studentId);
                if (CollectionUtils.isNotEmpty(list) && list.size() > 0) {
                    groupResult.setJoinedStatus(YesNoNumberEnum.YES.getCode());
                }
            }
            //设置班级学生总数量
            this.setTotalCount(groupResult.getClassId(), new ArrayList<>(Collections.singletonList(groupResult)));
            //设置学生数量
            classGroupConvert.renderClassStudentCount(groupResult);


        }

        return groupResult;
    }

    @Override
    public List<ClassGroupResultDTO> findListByClassId(Long classId) {
        ClassGroupQueryDTO query = new ClassGroupQueryDTO();
        query.setClassId(classId);
        List<ClassGroupResultDTO> groupList = list(wrapper(query)).stream().map(classGroupConvert::convert).collect(Collectors.toList());
        //设置子分组
        return classGroupConvert.renderClassGroupTree(groupList);
    }

    @Override
    public Long findParentGroupCountByClassId(Long classId, String type) {
        ClassGroupQueryDTO queryDTO = new ClassGroupQueryDTO();
        queryDTO.setClassId(classId);
        queryDTO.setType(type);
        queryDTO.setPid(0L);
        return count(wrapper(queryDTO));
    }

    @Override
    public Long findParentGroupCountByClassIdAndTypes(Long classId, List<String> types) {
        return count(wrapperByClassIdAndTypes(classId, 0L, types));
    }

    @Override
    public List<ClassGroupResultDTO> findListByGroupStudentIds(List<Long> idList) {
        return baseMapper.findListByGroupStudentIds(idList);
    }

    @Override
    public List<ClassGroupEntity> findByClassIdList(List<Long> classIdList) {
        LambdaQueryWrapper<ClassGroupEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(ClassGroupEntity::getClassId, classIdList);
        return list(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeBatchByIds(List<Long> groupIds) {
        deletedByIds(groupIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transferCourseClassGroupList(Long newCourseId, List<ClassGroupEntity> classGroupList) {
        classGroupList.forEach(s -> s.setCourseId(newCourseId));
        saveOrUpdateBatch(classGroupList);
    }

    @Override
    public List<ClassGroupEntity> getByGroupIds(List<Long> groupIds) {
        LambdaQueryWrapper<ClassGroupEntity> groupQuery = new LambdaQueryWrapper<>();
        groupQuery.in(ClassGroupEntity::getId, groupIds);
        return baseMapper.selectList(groupQuery);
    }
}
